#pragma once
#include "Decoder.h"

#include <stdio.h>
#include <fstream>
#include <sstream>

//#define MINIMP3_ONLY_MP3
//#define MINIMP3_ONLY_SIMD
//#define MINIMP3_NO_SIMD
//#define MINIMP3_NONSTANDARD_BUT_LOGICAL
#define MINIMP3_IMPLEMENTATION
#include "minimp3.h"

class Mp3Decoder : public Decoder<short>
{
public:
    virtual bool decode(const std::string& filename, Sound<short>& sound)
    {
        char* mp3_buf = NULL;
        int mp3_size = 0;
        {
            std::ifstream in;
            in.open(filename.c_str(), std::ios::in|std::ios::binary);
            if (!in.is_open())
            {
                return false;
            }
            in.seekg(0, std::ios::end);
            mp3_size = in.tellg();
            in.seekg(0, std::ios::beg);
            mp3_buf = new char[mp3_size];
            in.read(mp3_buf, mp3_size*sizeof(char));
            
            in.close();
        }

        const unsigned char* buf_mp3 = (const unsigned char*)&mp3_buf[0];
        

        mp3dec_t mp3d;
        mp3dec_frame_info_t info;

        mp3dec_init(&mp3d);
        memset(&info, 0, sizeof(info));

        do
        {
            short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];

            int samples = mp3dec_decode_frame(&mp3d, buf_mp3, mp3_size, pcm, &info);

            if (sound._pcm.empty())
            {
                sound._pcm.resize(info.channels);
                sound._hz = info.hz;
            }

            if (samples)
            {
                int count = MINIMP3_MAX_SAMPLES_PER_FRAME / info.channels;
                for (int i = 0; i < count; i++)
                {
                    for (int j = 0; j < info.channels; j++)
                    {
                        sound._pcm[j].push_back(pcm[i*info.channels + j]);
                    }
                }
            }
            buf_mp3 += info.frame_bytes;
            mp3_size -= info.frame_bytes;
        } while (info.frame_bytes);
        
        delete[] mp3_buf;

        return true;

    }
};